// 
//   QuickDev.Common.Utils - http://subsonicproject.com
// 
//   The contents of file are subject to the New BSD
//   License (the "License"); you may not use file
//   except in compliance with the License. You may obtain a copy of
//   the License at http://www.opensource.org/licenses/bsd-license.php
//  
//   Software distributed under the License is distributed on an 
//   "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
//   implied. See the License for the specific language governing
//   rights and limitations under the License.
// 
using System.IO;
using System.Net;
using System;
using System.Collections;

namespace QuickDev.Common.Utils
{
    /// <summary>
    /// Summary for the Files class
    /// </summary>
    public static class IO
    {
        #region Constants

        private const string PATH = "path";
        private const string FILE_EXISTS = "The file already exists.";
        private const string DIRECTORY_DOES_NOT_EXIST = "Directory does not exist: {0}";

        #endregion

        #region CreateDirectory

        /// <summary>
        /// Create Path
        /// </summary>
        /// <param name="path">path</param>
        public static void CreateDirectory( string path )
        {
            Validation.ValidateStringArgumentIsNotNullOrEmptyString( path , PATH );

            if ( !Directory.Exists( path ) )
            {
                Directory.CreateDirectory( path );
            }
        }

        #endregion

        #region Files

        /// <summary>
        /// Write( string path , Stream stream )
        /// </summary>
        /// <param name="path">path</param>
        /// <param name="stream">stream</param>
        public static void Write( string path , Stream stream )
        {
            Validation.ValidateStringArgumentIsNotNullOrEmptyString( path , PATH );
            if ( File.Exists( path ) )
            {
                throw new ArgumentException( FILE_EXISTS , PATH );
            }

            string directoryName = Path.GetDirectoryName( path );
            if ( !Directory.Exists( directoryName ) )
            {
                throw new DirectoryNotFoundException( string.Format( DIRECTORY_DOES_NOT_EXIST , directoryName ) );
            }

            FileStream fileStream = new FileStream( path , FileMode.Create , FileAccess.Write );
            byte[] buffer = new byte[4096];
            int bytesRead;
            while ( ( bytesRead = stream.Read( buffer , 0 , 4096 ) ) > 0 )
            {
                fileStream.Write( buffer , 0 , bytesRead );
            }
            fileStream.Flush();
            fileStream.Close();
        }

        /// <summary>
        /// Display bytes as a suitable unit of measurement.
        /// </summary>
        /// <remarks>
        /// Uses 1024^x for the units as used by memory and file sizing. Do not use in
        /// telecommunications where 1000^x is the norm.
        /// </remarks>
        /// <param name="bytes">Number of bytes to display.</param>
        /// <returns>A String formatted with the number of bytes and suitable unit of measurement.</returns>
        public static string FromByteCount( long bytes )
        {
            const decimal kilobyte = 1024m;
            const decimal megabyte = kilobyte * 1024;
            const decimal gigabyte = megabyte * 1024;

            if ( bytes > gigabyte )
                return String.Format( "{0:0.00} GB" , bytes / gigabyte );
            if ( bytes > megabyte )
                return String.Format( "{0:0.00} MB" , bytes / megabyte );
            if ( bytes > kilobyte )
                return String.Format( "{0:0.00} KB" , bytes / kilobyte );
            return String.Format( "{0} B" , bytes );
        }

        /// <summary>
        /// Read a text file and obtain it's contents.
        /// </summary>
        /// <param name="absolutePath">The complete file path to write to.</param>
        /// <returns>String containing the content of the file.</returns>
        public static string GetFileText( string absolutePath )
        {
            using ( StreamReader sr = new StreamReader( absolutePath ) )
                return sr.ReadToEnd();
        }

        /// <summary>
        /// Creates or opens a file for writing and writes text to it.
        /// </summary>
        /// <param name="absolutePath">The complete file path to write to.</param>
        /// <param name="fileText">A String containing text to be written to the file.</param>
        public static void CreateToFile( string fileText , string absolutePath )
        {
            using ( StreamWriter sw = File.CreateText( absolutePath ) )
                sw.Write( fileText );
        }

        /// <summary>
        /// Update text within a file by replacing a substring within the file.
        /// </summary>
        /// <param name="absolutePath">The complete file path to write to.</param>
        /// <param name="lookFor">A String to be replaced.</param>
        /// <param name="replaceWith">A String to replace all occurrences of lookFor.</param>
        public static void UpdateFileText( string absolutePath , string lookFor , string replaceWith )
        {
            string newText = GetFileText( absolutePath ).Replace( lookFor , replaceWith );
            WriteToFile( absolutePath , newText );
        }

        /// <summary>
        /// Writes out a string to a file.
        /// </summary>
        /// <param name="absolutePath">The complete file path to write to.</param>
        /// <param name="fileText">A String containing text to be written to the file.</param>
        public static void WriteToFile( string absolutePath , string fileText )
        {
            using ( StreamWriter sw = new StreamWriter( absolutePath , false ) )
                sw.Write( fileText );
        }

        /// <summary>
        /// append text to an existed file
        /// </summary>
        /// <param name="absolutePath">The complete file path to write to.</param>
        /// <param name="fileText">A String containing text to be written to the file.</param>
        public static void AppendToFile( string absolutePath , string fileText )
        {
            using ( StreamWriter sw = File.AppendText( absolutePath ) )
                sw.Write( fileText );
        }

        #endregion

        #region TextFile

        /// <summary>
        /// Reads the contents of a text file.
        /// </summary>
        /// <param name="fileName">file to read from</param>
        /// <returns>each line of the file</returns>
        public static string[] ReadFile( string fileName )
        {
            TextReader t = null;
            string[] result = null;

            try
            {
                t = File.OpenText( fileName );
                ArrayList lines = new ArrayList();
                string line;
                while ( ( (string)( line = t.ReadLine() ) ) != null )
                {
                    if ( line.Length > 0 )
                        lines.Add( line );
                }
                result = new string[lines.Count];
                lines.CopyTo( result );
            }
            finally
            {
                if ( t != null )
                    t.Close();
            }

            return result;
        }

        /// <summary>
        /// Writes a string to a text file.
        /// </summary>
        /// <param name="data">lines to write</param>
        /// <param name="fileName">file to write to</param>
        public static void WriteFile( string fileName , string[] data )
        {
            TextWriter t = null;

            try
            {
                string dir = Path.GetDirectoryName( fileName );

                if ( !Directory.Exists( dir ) )
                    Directory.CreateDirectory( dir );

                t = File.CreateText( fileName );

                foreach ( string line in data )
                    t.WriteLine( line );
            }
            finally
            {
                if ( t != null )
                    t.Close();
            }
        }

        #endregion
    }
}